#include "http_server.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <libgen.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>

HttpServer::HttpServer(int port, const std::string& bind_address) 
    : port(port), bind_address(bind_address), running(false) {
}

HttpServer::~HttpServer() {
    stop();
}

void HttpServer::start() {
    if (running) {
        return;
    }
    
    running = true;
    server_thread = std::make_unique<std::thread>(&HttpServer::run, this);
}

void HttpServer::stop() {
    if (!running) {
        return;
    }
    
    running = false;
    if (server_thread && server_thread->joinable()) {
        server_thread->join();
    }
}

void HttpServer::run() {
    int server_fd;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    
    // 创建socket文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        std::cerr << "Socket creation failed" << std::endl;
        return;
    }
    
    // 设置socket选项
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        std::cerr << "Setsockopt failed" << std::endl;
        close(server_fd);
        return;
    }
    
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(bind_address.c_str());
    address.sin_port = htons(port);
    
    // 绑定socket到指定地址和端口
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        std::cerr << "Bind failed" << std::endl;
        close(server_fd);
        return;
    }
    
    // 开始监听连接
    if (listen(server_fd, 3) < 0) {
        std::cerr << "Listen failed" << std::endl;
        close(server_fd);
        return;
    }
    
    // 设置socket为非阻塞模式，以便能够及时响应停止请求
    int flags = fcntl(server_fd, F_GETFL, 0);
    fcntl(server_fd, F_SETFL, flags | O_NONBLOCK);
    
    std::cout << "HTTP Server started on " << bind_address << ":" << port << std::endl;
    
    while (running) {
        int new_socket;
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            // 在非阻塞模式下，如果没有连接到达，errno会被设置为EAGAIN或EWOULDBLOCK
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 等待一小段时间再重试，以便能够及时响应停止请求
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                continue;
            }
            
            if (running) {
                std::cerr << "Accept failed" << std::endl;
            }
            break;
        }
        
        // 读取请求
        char buffer[30000] = {0};
        read(new_socket, buffer, 30000);
        
        // 解析请求行
        std::string request(buffer);
        std::istringstream iss(request);
        std::string method, path, protocol;
        iss >> method >> path >> protocol;
        
        std::cout << "Request: " << method << " " << path << " " << protocol << std::endl;
        
        // 处理请求
        std::string response;
        if (method == "GET") {
            std::cout << path.substr(0,6) << std::endl;
            if (path == "/" || path.substr(0, 7) == "/3.html") {
                // 提供3.html文件
                std::string file_path = "UI/3.html";
                std::string content = read_file(file_path);

                //替换 其中 的{myak} 为 oNAXLkfVpfzHpTE3HlCpWR82jhLo8VlC
                content = content.replace(content.find("{myak}"), 6, "oNAXLkfVpfzHpTE3HlCpWR82jhLo8VlC");
                
                if (!content.empty()) {
                    std::string content_type = get_content_type(file_path);
                    response = "HTTP/1.1 200 OK\r\n";
                    response += "Content-Type: " + content_type + "\r\n";
                    response += "Content-Length: " + std::to_string(content.length()) + "\r\n";
                    response += "Connection: close\r\n";
                    response += "\r\n";
                    response += content;
                } else {
                    // 文件未找到
                    response = "HTTP/1.1 404 Not Found\r\n";
                    response += "Content-Type: text/html\r\n";
                    response += "Content-Length: 22\r\n";
                    response += "Connection: close\r\n";
                    response += "\r\n";
                    response += "<h1>404 Not Found</h1>";
                }
            } else {
                // 其他路径返回404
                response = "HTTP/1.1 404 Not Found\r\n";
                response += "Content-Type: text/html\r\n";
                response += "Content-Length: 22\r\n";
                response += "Connection: close\r\n";
                response += "\r\n";
                response += "<h1>404 Not Found</h1>";
            }
        } else {
            // 不支持的方法
            response = "HTTP/1.1 405 Method Not Allowed\r\n";
            response += "Content-Type: text/html\r\n";
            response += "Content-Length: 30\r\n";
            response += "Connection: close\r\n";
            response += "\r\n";
            response += "<h1>405 Method Not Allowed</h1>";
        }
        
        // 发送响应
        send(new_socket, response.c_str(), response.length(), 0);
        close(new_socket);
    }
    
    close(server_fd);
    std::cout << "HTTP Server stopped" << std::endl;
}

std::string HttpServer::get_content_type(const std::string& path) {
    // 根据文件扩展名确定Content-Type
    if (path.substr(path.find_last_of(".") + 1) == "html") {
        return "text/html; charset=utf-8";
    } else if (path.substr(path.find_last_of(".") + 1) == "js") {
        return "application/javascript";
    } else if (path.substr(path.find_last_of(".") + 1) == "css") {
        return "text/css";
    } else {
        return "application/octet-stream";
    }
}

std::string HttpServer::read_file(const std::string& path) {
    std::ifstream file(path, std::ios::binary);
    if (!file.is_open()) {
        // 尝试在可执行文件目录下查找
        char* exec_path = realpath("/proc/self/exe", NULL);
        if (exec_path) {
            char* exec_dir = dirname(exec_path);
            std::string full_path = std::string(exec_dir) + "/" + path;
            free(exec_path);
            
            file.open(full_path, std::ios::binary);
        }
    }
    
    if (!file.is_open()) {
        std::cerr << "Failed to open file: " << path << std::endl;
        return "";
    }
    
    std::stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}